<template>
  <div v-if="!single">
    <dragSize
      v-for="item in dialogList"
      :key="item.RID"
      :kvm="item"
      :drag-min-height="560"
      :drag-min-width="880"
      :p-index="item.RID"
      :is-show="true"
      :z-index="item.zIndex || 10000"
      @selectItem="topDialog"
      @openNew="openFunc"
      @close="beforeClose"
    >
      <div
        class="dialog_content terminal-window"
        :id="item.RID"
        :style="{ zIndex: item.zIndex || 10000 }"
        :class="{ 'active-terminal': currentRID === item.RID }"
        @click="topDialog(item)"
      >
        <div v-loading="radioMap[item.RID].loading" style="height: 100%">
          <div class="terminal-container">
            <!-- 悬浮控制按钮 -->
            <div class="floating-controls">
              <!-- 只读状态指示器 -->
              <div
                v-if="showReadonlyIndicator"
                class="control-indicator status-readonly-indicator"
                :class="{ active: radioMap[item.RID].read }"
                :title="radioMap[item.RID].read ? '只读模式' : '可编辑模式'"
                @click="toggleReadOnly"
              >
                <svg
                  v-if="!radioMap[item.RID].read"
                  width="20"
                  height="20"
                  viewBox="0 0 24 24"
                  fill="none"
                  xmlns="http://www.w3.org/2000/svg"
                >
                  <path
                    d="M20.71 7.04c.39-.39.39-1.04 0-1.41l-2.34-2.34c-.37-.39-1.02-.39-1.41 0l-1.84 1.83 3.75 3.75M3 17.25V21h3.75L17.81 9.93l-3.75-3.75L3 17.25z"
                    stroke="currentColor"
                    stroke-width="2"
                    stroke-linecap="round"
                    stroke-linejoin="round"
                  />
                </svg>
                <svg
                  v-else
                  width="20"
                  height="20"
                  viewBox="0 0 24 24"
                  fill="none"
                  xmlns="http://www.w3.org/2000/svg"
                >
                  <path
                    d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z"
                    fill="currentColor"
                  />
                </svg>
              </div>

              <!-- 软键盘按钮 -->
              <div
                class="control-indicator keyboard-indicator"
                title="打开VNC配置 (Ctrl+Shift+Alt)"
                @click="openSystemKeyboard(item)"
              >
                <svg
                  width="20"
                  height="20"
                  viewBox="0 0 24 24"
                  fill="none"
                  xmlns="http://www.w3.org/2000/svg"
                >
                  <path
                    d="M12 15C13.6569 15 15 13.6569 15 12C15 10.3431 13.6569 9 12 9C10.3431 9 9 10.3431 9 12C9 13.6569 10.3431 15 12 15Z"
                    stroke="currentColor"
                    stroke-width="2"
                    stroke-linecap="round"
                    stroke-linejoin="round"
                  />
                  <path
                    d="M19.4 15C19.2669 15.3016 19.2272 15.6362 19.286 15.9606C19.3448 16.285 19.4995 16.5843 19.73 16.82L19.79 16.88C19.976 17.0657 20.1235 17.2863 20.2241 17.5291C20.3248 17.7719 20.3766 18.0322 20.3766 18.295C20.3766 18.5578 20.3248 18.8181 20.2241 19.0609C20.1235 19.3037 19.976 19.5243 19.79 19.71C19.6043 19.896 19.3837 20.0435 19.1409 20.1441C18.8981 20.2448 18.6378 20.2966 18.375 20.2966C18.1122 20.2966 17.8519 20.2448 17.6091 20.1441C17.3663 20.0435 17.1457 19.896 16.96 19.71L16.9 19.65C16.6643 19.4195 16.365 19.2648 16.0406 19.206C15.7162 19.1472 15.3816 19.1869 15.08 19.32C14.7842 19.4468 14.532 19.6572 14.3543 19.9255C14.1766 20.1938 14.0813 20.5082 14.08 20.83V21C14.08 21.5304 13.8693 22.0391 13.4942 22.4142C13.1191 22.7893 12.6104 23 12.08 23C11.5496 23 11.0409 22.7893 10.6658 22.4142C10.2907 22.0391 10.08 21.5304 10.08 21V20.91C10.0723 20.579 9.96512 20.258 9.77251 19.9887C9.5799 19.7194 9.31074 19.5143 9 19.4C8.69838 19.2669 8.36381 19.2272 8.03941 19.286C7.71502 19.3448 7.41568 19.4995 7.18 19.73L7.12 19.79C6.93425 19.976 6.71368 20.1235 6.47088 20.2241C6.22808 20.3248 5.96783 20.3766 5.705 20.3766C5.44217 20.3766 5.18192 20.3248 4.93912 20.2241C4.69632 20.1235 4.47575 19.976 4.29 19.79C4.10405 19.6043 3.95653 19.3837 3.85588 19.1409C3.75523 18.8981 3.70343 18.6378 3.70343 18.375C3.70343 18.1122 3.75523 17.8519 3.85588 17.6091C3.95653 17.3663 4.10405 17.1457 4.29 16.96L4.35 16.9C4.58054 16.6643 4.73519 16.365 4.794 16.0406C4.85282 15.7162 4.81312 15.3816 4.68 15.08C4.55324 14.7842 4.34276 14.532 4.07447 14.3543C3.80618 14.1766 3.49179 14.0813 3.17 14.08H3C2.46957 14.08 1.96086 13.8693 1.58579 13.4942C1.21071 13.1191 1 12.6104 1 12.08C1 11.5496 1.21071 11.0409 1.58579 10.6658C1.96086 10.2907 2.46957 10.08 3 10.08H3.09C3.42099 10.0723 3.742 9.96512 4.0113 9.77251C4.28059 9.5799 4.48572 9.31074 4.6 9C4.73312 8.69838 4.77282 8.36381 4.714 8.03941C4.65519 7.71502 4.50054 7.41568 4.27 7.18L4.21 7.12C4.02405 6.93425 3.87653 6.71368 3.77588 6.47088C3.67523 6.22808 3.62343 5.96783 3.62343 5.705C3.62343 5.44217 3.67523 5.18192 3.77588 4.93912C3.87653 4.69632 4.02405 4.47575 4.21 4.29C4.39575 4.10405 4.61632 3.95653 4.85912 3.85588C5.10192 3.75523 5.36217 3.70343 5.625 3.70343C5.88783 3.70343 6.14808 3.75523 6.39088 3.85588C6.63368 3.95653 6.85425 4.10405 7.04 4.29L7.1 4.35C7.33568 4.58054 7.63502 4.73519 7.95941 4.794C8.28381 4.85282 8.61838 4.81312 8.92 4.68H9C9.29577 4.55324 9.54802 4.34276 9.72569 4.07447C9.90337 3.80618 9.99872 3.49179 10 3.17V3C10 2.46957 10.2107 1.96086 10.5858 1.58579C10.9609 1.21071 11.4696 1 12 1C12.5304 1 13.0391 1.21071 13.4142 1.58579C13.7893 1.96086 14 2.46957 14 3V3.09C14.0013 3.41179 14.0966 3.72618 14.2743 3.99447C14.452 4.26276 14.7042 4.47324 15 4.6C15.3016 4.73312 15.6362 4.77282 15.9606 4.714C16.285 4.65519 16.5843 4.50054 16.82 4.27L16.88 4.21C17.0657 4.02405 17.2863 3.87653 17.5291 3.77588C17.7719 3.67523 18.0322 3.62343 18.295 3.62343C18.5578 3.62343 18.8181 3.67523 19.0609 3.77588C19.3037 3.87653 19.5243 4.02405 19.71 4.21C19.896 4.39575 20.0435 4.61632 20.1441 4.85912C20.2448 5.10192 20.2966 5.36217 20.2966 5.625C20.2966 5.88783 20.2448 6.14808 20.1441 6.39088C20.0435 6.63368 19.896 6.85425 19.71 7.04L19.65 7.1C19.4195 7.33568 19.2648 7.63502 19.206 7.95941C19.1472 8.28381 19.1869 8.61838 19.32 8.92V9C19.4468 9.29577 19.6572 9.54802 19.9255 9.72569C20.1938 9.90337 20.5082 9.99872 20.83 10H21C21.5304 10 22.0391 10.2107 22.4142 10.5858C22.7893 10.9609 23 11.4696 23 12C23 12.5304 22.7893 13.0391 22.4142 13.4142C22.0391 13.7893 21.5304 14 21 14H20.91C20.5882 14.0013 20.2738 14.0966 20.0055 14.2743C19.7372 14.452 19.5268 14.7042 19.4 15Z"
                    stroke="currentColor"
                    stroke-width="2"
                    stroke-linecap="round"
                    stroke-linejoin="round"
                  />
                </svg>
              </div>
            </div>

            <div
              class="virtualIframe"
              :class="{ 'full-height': radioMap[item.RID].read }"
            >
              <div
                :class="[
                  'iframeMain',
                  radioMap[item.RID].read ? 'readonly' : '',
                ]"
              >
                <!--靶标连接处理-->
                <iframe
                  :id="'Terminal' + item.RID"
                  v-if="item.linkType"
                  :src="item.uri"
                  width="100%"
                  height="100%"
                  allow="fullscreen; microphone; geolocation; camera"
                  sandbox="allow-same-origin allow-scripts allow-forms allow-modals"
                />

                <iframe
                  :id="'Terminal' + item.RID"
                  v-else
                  :src="
                    item.uri ? origin + '/console/#/client/' + item.uri : null
                  "
                  width="100%"
                  height="100%"
                  allow="fullscreen; microphone; geolocation; camera"
                  sandbox="allow-same-origin allow-scripts allow-forms allow-modals"
                />
                <!-- 添加文本选择覆盖层 -->
                <div class="text-selection-overlay">
                  <div class="selection-area"></div>
                </div>
              </div>
              <div
                :class="['mask', currentRID === item.RID ? 'active' : '']"
                @click="topDialog(item)"
              />
              <div class="iframe-loading" v-if="radioMap[item.RID].loading">
                <div class="loading-spinner"></div>
              </div>
            </div>

            <!-- 命令输入控制台 -->
            <div
              class="command-console"
              v-if="!radioMap[item.RID].read"
              @click.stop="handleCommandInputClick(item)"
            >
              <div class="console-prefix">$</div>
              <input
                type="text"
                class="console-input"
                v-model="commandInputs[item.RID]"
                @keydown.enter="sendCommand(item)"
                @input="handleInput"
                @keydown.stop
                @click.stop="handleCommandInputClick(item)"
                @mousedown.stop
                @mouseup.stop
                placeholder="输入命令，回车发送（不支持中文）"
                @focus="currentCommandItem = item"
                :id="'CommandInput' + item.RID"
                autocomplete="off"
              />
              <div
                class="console-send-btn"
                @click.stop="sendCommand(item)"
                title="发送命令"
              >
                <svg
                  viewBox="0 0 24 24"
                  width="20"
                  height="20"
                  stroke="currentColor"
                  stroke-width="2"
                  fill="none"
                  stroke-linecap="round"
                  stroke-linejoin="round"
                >
                  <line x1="22" y1="2" x2="11" y2="13"></line>
                  <polygon points="22 2 15 22 11 13 2 9 22 2"></polygon>
                </svg>
              </div>
            </div>
          </div>
        </div>
      </div>
    </dragSize>
  </div>
  <div class="virtualIframe" v-else>
    <div v-for="item in dialogList" :key="item.RID">
      <iframe
        :id="'Terminal' + item.RID"
        :src="item.uri ? origin + '/console/#/client/' + item.uri : null"
        width="100%"
        height="100%"
        allow="fullscreen; microphone; geolocation; camera"
        sandbox="allow-same-origin allow-scripts allow-forms allow-modals"
      />
    </div>
  </div>
</template>

<script setup lang="ts">
import {
  nextTick,
  ref,
  defineExpose,
  onMounted,
  onBeforeUnmount,
  computed,
  watch,
  reactive,
} from 'vue';
import { getVirtual } from '@/api/topo/topo.js';
import dragSize from './dragSize.vue';
import { getTerminalVMInfo } from '@/api/topo/terminal';
import { ElMessage } from 'element-plus';

// 定义item类型接口
interface DialogItem {
  RID: string;
  id?: string | number;
  zIndex?: number;
  linkType?: boolean;
  uri?: string;
  token?: string;
}

// 父组件事件
const emit = defineEmits(['closeDialog', 'topDialog']);
const props = defineProps({
  dialogList: {
    default: function () {
      return [] as DialogItem[];
    },
    type: Array as () => DialogItem[],
  },
  single: Boolean,
  type: String,
  showReadonlyIndicator: {
    type: Boolean,
    default: true,
  },
});

// 标题和只读状态
const title = ref('Virtual Terminal');
const isReadonly = ref(false);

// 虚拟键盘状态
const showVirtualKeyboard = ref(false);
const isShiftActive = ref(false);

// 监听只读状态变化
watch(isReadonly, newValue => {
  if (currentRID.value) {
    // 更新当前终端的只读状态
    radioMap.value[currentRID.value].read = newValue;

    // 获取当前终端实例
    const currentItem = props.dialogList.find(
      item => item.RID === currentRID.value,
    );
    if (currentItem) {
      changeVirtual(currentItem);
    }
  }
});

/**
 * 关闭控制台
 */
const closeConsole = () => {
  if (currentRID.value) {
    const currentItem = props.dialogList.find(
      item => item.RID === currentRID.value,
    );
    if (currentItem) {
      beforeClose(currentItem);
    }
  }
};

/**
 * 切换全屏
 */
const toggleFullScreen = () => {
  const terminalElement = document.getElementById(currentRID.value || '');
  if (!terminalElement) return;

  if (!document.fullscreenElement) {
    terminalElement.requestFullscreen().catch(err => {
      ElMessage.error(`全屏模式错误: ${err.message}`);
    });
  } else {
    if (document.exitFullscreen) {
      document.exitFullscreen();
    }
  }
};

/**
 * 刷新终端
 */
const refreshUrl = () => {
  if (currentRID.value) {
    radioMap.value[currentRID.value].loading = true;

    const currentItem = props.dialogList.find(
      item => item.RID === currentRID.value,
    );
    if (currentItem) {
      const iframe = document.getElementById(
        'Terminal' + currentItem.RID,
      ) as HTMLIFrameElement;
      if (iframe) {
        const currentSrc = iframe.src;
        iframe.src = 'about:blank';
        setTimeout(() => {
          iframe.src = currentSrc;
          radioMap.value[currentRID.value!].loading = false;
        }, 500);
      }
    }
  }
};

// 添加当前时间显示
const currentTime = computed(() => {
  const now = new Date();
  const hours = String(now.getHours()).padStart(2, '0');
  const minutes = String(now.getMinutes()).padStart(2, '0');
  const seconds = String(now.getSeconds()).padStart(2, '0');
  return `${hours}:${minutes}:${seconds}`;
});

onMounted(() => {
  window.addEventListener('keydown', handleKeyDown);

  // 添加文本选择功能
  setupTextSelection();
});

onBeforeUnmount(() => {
  window.removeEventListener('keydown', handleKeyDown);
});

// 源地址信息
const origin = ref('');
const mode = import.meta.env.MODE;
origin.value =
  mode === 'development' ? 'https://172.19.4.225' : window.location.origin;

//保存read、loading等信息
const radioMap = ref<
  Record<string, { read: boolean; record: boolean; loading: boolean }>
>({});
const currentRID = ref<string>();

// 命令输入相关
const commandInputs = ref<Record<string, string>>({});
const commandHistories = ref<Record<string, string[]>>({});
const historyIndices = ref<Record<string, number>>({});
const currentCommandItem = ref<DialogItem | null>(null);

/**
 * 初始化终端的命令历史记录
 */
const initTerminalHistory = (rid: string) => {
  if (!commandHistories.value[rid]) {
    commandHistories.value[rid] = [];
  }
  if (historyIndices.value[rid] === undefined) {
    historyIndices.value[rid] = -1;
  }
  if (commandInputs.value[rid] === undefined) {
    commandInputs.value[rid] = '';
  }
};

/**
 * 聚焦到命令输入框
 */
const focusCommandInput = () => {
  nextTick(() => {
    try {
      const activeRID = currentRID.value;
      if (!activeRID) return;

      // 确保iframe不会获取焦点
      const iframe = document.getElementById(
        'Terminal' + activeRID,
      ) as HTMLIFrameElement;
      if (iframe) {
        iframe.style.pointerEvents = 'none';
        iframe.blur();
      }

      // 聚焦到输入框
      setTimeout(() => {
        const inputElement = document.getElementById(
          'CommandInput' + activeRID,
        );
        if (inputElement) {
          inputElement.focus();
        }
      }, 200);

      // 短暂延迟后恢复iframe的指针事件
      setTimeout(() => {
        if (iframe) {
          iframe.style.pointerEvents = 'auto';
        }
      }, 300);
    } catch (e) {
      console.error('聚焦输入框失败:', e);
    }
  });
};

/**
 * 发送命令到虚拟机
 * @param item 虚拟机项
 */
const sendCommand = (item: DialogItem) => {
  const input = commandInputs.value[item.RID];
  if (!input?.trim()) return;

  // 检查是否包含中文字符
  if (/[\u4e00-\u9fa5]/.test(input)) {
    ElMessage.warning('不支持输入中文，请使用英文');
    return;
  }

  // 初始化该终端的历史记录
  initTerminalHistory(item.RID);

  // 记录到历史
  commandHistories.value[item.RID].push(input);
  if (commandHistories.value[item.RID].length > 50) {
    commandHistories.value[item.RID].shift(); // 保留最近50条命令
  }
  historyIndices.value[item.RID] = -1;

  // 发送命令到虚拟机，确保包含回车符
  const command = input + '\r\n'; // 使用 \r\n 作为回车换行符
  sendTextToVirtualMachine(item, command);

  // 清空当前终端的输入框
  commandInputs.value[item.RID] = '';

  // 重新聚焦输入框，并确保焦点不会切换到虚拟机内部
  nextTick(() => {
    const inputElement = document.getElementById('CommandInput' + item.RID);
    if (inputElement) {
      // 确保iframe不会获取焦点
      const iframe = document.getElementById(
        'Terminal' + item.RID,
      ) as HTMLIFrameElement;
      if (iframe) {
        iframe.style.pointerEvents = 'none';
        iframe.blur();
      }

      // 聚焦到输入框
      inputElement.focus();

      // 短暂延迟后恢复iframe的指针事件
      setTimeout(() => {
        if (iframe) {
          iframe.style.pointerEvents = 'auto';
        }
      }, 100);
    }
  });
};

/**
 * 发送文本到虚拟机
 * @param item 虚拟机项
 * @param text 要发送的文本
 */
const sendTextToVirtualMachine = (item: DialogItem, text: string) => {
  const iframe = document.getElementById('Terminal' + item.RID);
  if (!iframe) {
    ElMessage.error('虚拟机未加载');
    return;
  }

  try {
    // 发送文本到虚拟机
    setTimeout(() => {
      try {
        const htmlIframe = iframe as HTMLIFrameElement;
        const iframeDocument =
          htmlIframe.contentDocument || htmlIframe.contentWindow?.document;
        if (!iframeDocument) {
          ElMessage.error('无法访问虚拟机文档');
          return;
        }

        // 中文和复杂字符处理
        if (containsNonAscii(text)) {
          // 使用剪贴板API处理
          try {
            // 尝试使用Clipboard API
            navigator.clipboard
              .writeText(text)
              .then(() => {
                // 模拟Ctrl+V粘贴
                const pasteEvent = new KeyboardEvent('keydown', {
                  key: 'v',
                  code: 'KeyV',
                  keyCode: 86,
                  which: 86,
                  ctrlKey: true,
                  bubbles: true,
                });
                iframeDocument.dispatchEvent(pasteEvent);
              })
              .catch(() => {
                // 如果Clipboard API失败，使用备用方法
                fallbackSendText(text, iframeDocument);
              });
          } catch (e) {
            // 如果Clipboard API不可用，使用备用方法
            fallbackSendText(text, iframeDocument);
          }
        } else {
          // 对于ASCII字符，直接发送
          const activeElement = iframeDocument.activeElement as HTMLElement;
          if (activeElement) {
            // 创建一个input事件
            const inputEvent = new InputEvent('input', {
              data: text,
              inputType: 'insertText',
              bubbles: true,
            });
            activeElement.dispatchEvent(inputEvent);
          }
        }
      } catch (e) {
        console.error('发送命令失败:', e);
        ElMessage.error('发送命令失败');
      }
    }, 100);
  } catch (err) {
    console.error('发送命令失败:', err);
    ElMessage.error('发送命令失败');
  }
};

/**
 * 备用方法发送文本到虚拟机
 */
const fallbackSendText = (text: string, iframeDocument: Document) => {
  // 备用方法1: 使用execCommand
  try {
    const activeElement = iframeDocument.activeElement as HTMLElement;
    if (activeElement && typeof activeElement.textContent !== 'undefined') {
      iframeDocument.execCommand('insertText', false, text);

      // 如果是命令，模拟回车键
      if (text.endsWith('\n')) {
        setTimeout(() => {
          const enterEvent = new KeyboardEvent('keydown', {
            key: 'Enter',
            code: 'Enter',
            keyCode: 13,
            which: 13,
            bubbles: true,
          });
          activeElement.dispatchEvent(enterEvent);
        }, 50);
      }
      return;
    }
  } catch (e) {
    console.warn('execCommand方法失败', e);
  }

  // 备用方法2: 直接向HTMLInputElement赋值
  try {
    if (iframeDocument.activeElement instanceof HTMLInputElement) {
      const inputEl = iframeDocument.activeElement;
      const originalValue = inputEl.value;
      inputEl.value = originalValue + text;

      // 触发input事件
      inputEl.dispatchEvent(new Event('input', { bubbles: true }));

      // 如果是命令，模拟回车键
      if (text.endsWith('\n')) {
        inputEl.dispatchEvent(
          new KeyboardEvent('keydown', {
            key: 'Enter',
            code: 'Enter',
            keyCode: 13,
            which: 13,
            bubbles: true,
          }),
        );
      }
      return;
    }
  } catch (e) {
    console.warn('直接操作DOM元素失败', e);
  }

  // 备用方法3: 逐个字符输入
  try {
    const chars = Array.from(text);
    for (let i = 0; i < chars.length; i++) {
      setTimeout(() => {
        simulateKeyPress(chars[i], iframeDocument);
      }, i * 100); // 对中文字符增加延迟
    }
  } catch (e) {
    console.warn('逐字输入失败', e);
  }
};

/**
 * 检查文本是否包含非ASCII字符
 */
const containsNonAscii = (text: string): boolean => {
  return /[^\x00-\x7F]/.test(text);
};

/**
 * 模拟键盘输入单个字符
 */
const simulateKeyPress = (char: string, document: Document) => {
  // 判断是否需要shift键（大写字母或特殊符号）
  const isUpperCase =
    char === char.toUpperCase() && char !== char.toLowerCase();
  const needsShift = isUpperCase || '~!@#$%^&*()_+{}|:"<>?'.includes(char);

  // 获取正确的key和code
  let key = char;
  let code = '';

  // 处理特殊字符的key code
  if (char.match(/[a-z]/i)) {
    code = 'Key' + char.toUpperCase();
  } else if (char.match(/[0-9]/)) {
    code = 'Digit' + char;
  } else if (char === ' ') {
    key = 'Space';
    code = 'Space';
  } else if (char === '\n') {
    key = 'Enter';
    code = 'Enter';
  } else {
    // 处理特殊符号
    switch (char) {
      case '!':
        key = '1';
        code = 'Digit1';
        break;
      case '@':
        key = '2';
        code = 'Digit2';
        break;
      case '#':
        key = '3';
        code = 'Digit3';
        break;
      case '$':
        key = '4';
        code = 'Digit4';
        break;
      case '%':
        key = '5';
        code = 'Digit5';
        break;
      case '^':
        key = '6';
        code = 'Digit6';
        break;
      case '&':
        key = '7';
        code = 'Digit7';
        break;
      case '*':
        key = '8';
        code = 'Digit8';
        break;
      case '(':
        key = '9';
        code = 'Digit9';
        break;
      case ')':
        key = '0';
        code = 'Digit0';
        break;
      case '-':
        key = '-';
        code = 'Minus';
        break;
      case '_':
        key = '-';
        code = 'Minus';
        break;
      case '=':
        key = '=';
        code = 'Equal';
        break;
      case '+':
        key = '=';
        code = 'Equal';
        break;
      case '[':
        key = '[';
        code = 'BracketLeft';
        break;
      case '{':
        key = '[';
        code = 'BracketLeft';
        break;
      case ']':
        key = ']';
        code = 'BracketRight';
        break;
      case '}':
        key = ']';
        code = 'BracketRight';
        break;
      case '\\':
        key = '\\';
        code = 'Backslash';
        break;
      case '|':
        key = '\\';
        code = 'Backslash';
        break;
      case ';':
        key = ';';
        code = 'Semicolon';
        break;
      case ':':
        key = ';';
        code = 'Semicolon';
        break;
      case "'":
        key = "'";
        code = 'Quote';
        break;
      case '"':
        key = "'";
        code = 'Quote';
        break;
      case ',':
        key = ',';
        code = 'Comma';
        break;
      case '<':
        key = ',';
        code = 'Comma';
        break;
      case '.':
        key = '.';
        code = 'Period';
        break;
      case '>':
        key = '.';
        code = 'Period';
        break;
      case '/':
        key = '/';
        code = 'Slash';
        break;
      case '?':
        key = '/';
        code = 'Slash';
        break;
      case '`':
        key = '`';
        code = 'Backquote';
        break;
      case '~':
        key = '`';
        code = 'Backquote';
        break;
      default:
        // 对于中文和其他非ASCII字符，尝试使用execCommand插入
        if (char.charCodeAt(0) > 127) {
          try {
            document.execCommand('insertText', false, char);
            return; // 如果成功插入，提前返回
          } catch (e) {
            console.warn('插入非ASCII字符失败', e);
          }
        }
        code = 'Unknown';
        break;
    }
  }

  // 如果需要Shift键
  if (needsShift) {
    // 按下Shift键
    const shiftDown = new KeyboardEvent('keydown', {
      key: 'Shift',
      code: 'ShiftLeft',
      shiftKey: true,
      bubbles: true,
    });
    document.dispatchEvent(shiftDown);
  }

  // 按键按下
  const keyDown = new KeyboardEvent('keydown', {
    key: key,
    code: code,
    shiftKey: needsShift,
    bubbles: true,
  });
  document.dispatchEvent(keyDown);

  // 触发keypress事件 (用于字符输入)
  const keyPress = new KeyboardEvent('keypress', {
    key: key,
    code: code,
    shiftKey: needsShift,
    bubbles: true,
  });
  document.dispatchEvent(keyPress);

  // 创建并触发input事件
  const inputEvent = new InputEvent('input', {
    data: char,
    inputType: 'insertText',
    bubbles: true,
  });

  // 查找可以接收输入的活动元素
  const activeElement = document.activeElement;
  if (activeElement) {
    activeElement.dispatchEvent(inputEvent);
  } else {
    document.body.dispatchEvent(inputEvent);
  }

  // 按键释放
  const keyUp = new KeyboardEvent('keyup', {
    key: key,
    code: code,
    shiftKey: needsShift,
    bubbles: true,
  });
  document.dispatchEvent(keyUp);

  // 如果需要Shift键，释放Shift键
  if (needsShift) {
    const shiftUp = new KeyboardEvent('keyup', {
      key: 'Shift',
      code: 'ShiftLeft',
      shiftKey: false,
      bubbles: true,
    });
    document.dispatchEvent(shiftUp);
  }
};

/**
 * 修改控制台状态
 * @param arg
 */
const changeVirtual = arg => {
  radioMap.value[arg.RID].loading = true;

  switch (props.type) {
    case 'scene':
      changeSceneVirtual(arg);
      break;
    case 'design':
      changeDesignVirtual(arg);
      break;
  }
};

/**
 * 修改场景管理控制台状态
 * @param arg
 */
const changeSceneVirtual = async arg => {
  getVirtual(arg.id, arg.RID, {
    read: radioMap.value[arg.RID].read,
    record: radioMap.value[arg.RID].record,
  }).then(async res => {
    if (!(res instanceof Error)) {
      const {
        data: { token },
      } = res;
      await setIframeInfo(arg, token);
      radioMap.value[arg.RID].loading = false;
    }
  });
};

/**
 * 修改场景设计虚拟机控制台状态
 * @param arg
 */
const changeDesignVirtual = async arg => {
  getTerminalVMInfo(arg.id, {
    read: radioMap.value[arg.RID].read,
    record: radioMap.value[arg.RID].record,
  }).then(async res => {
    if (!(res instanceof Error)) {
      const {
        data: { token },
      } = res;
      await setIframeInfo(arg, token);
      radioMap.value[arg.RID].loading = false;
    }
  });
};

/**
 * 打开弹窗
 * @param item
 */
const openFunc = async item => {
  radioMap.value[item.RID] = {
    read: false,
    record: false,
    loading: true,
  };
  await setIframeInfo(item, item.token);

  // 初始化该终端的历史记录
  initTerminalHistory(item.RID);

  // 在弹窗打开后自动聚焦命令输入框
  nextTick(() => {
    if (!radioMap.value[item.RID].read) {
      focusCommandInput();
    }
  });
};

/**
 * 设置iframe的token
 * @param item
 * @param token
 */
function setIframeInfo(item: DialogItem, token: string) {
  nextTick(() => {
    // 类型断言
    const iframeElement = document.getElementById('Terminal' + item.RID);
    if (!iframeElement) return;

    const htmlIframe = iframeElement as HTMLIFrameElement;

    if (htmlIframe.contentWindow) {
      htmlIframe.contentWindow.localStorage.setItem(
        'GUAC_AUTH',
        JSON.stringify({ authToken: token }),
      );
    }

    htmlIframe.onload = function () {
      // iframe加载完成后的处理
      if (htmlIframe.contentDocument || htmlIframe.contentWindow?.document) {
        const iframeDoc =
          htmlIframe.contentDocument || htmlIframe.contentWindow.document;
        iframeDoc.addEventListener('click', function () {
          topDialog(item);
          focusFunc(item);
        });
      }
    };

    htmlIframe.addEventListener('load', () => focusFunc(item));
    currentRID.value = item?.RID;

    if (htmlIframe.contentWindow && radioMap.value[item.RID].read) {
      htmlIframe.contentWindow.addEventListener('keydown', readonlyDocument);
      htmlIframe.contentWindow.addEventListener('mousedown', readonlyDocument);
    } else if (htmlIframe.contentWindow) {
      htmlIframe.contentWindow.removeEventListener('keydown', readonlyDocument);
      htmlIframe.contentWindow.removeEventListener(
        'mousedown',
        readonlyDocument,
      );
      focusFunc(item);
    }

    radioMap.value[item.RID].loading = false;
  });

  /**
   * 只读
   * @param event
   */
  function readonlyDocument(event: Event) {
    event && event.preventDefault();
  }
}

/**
 * 关闭弹窗
 * @param item
 */
function closeFunc(item: DialogItem) {
  const iframeElement = document.getElementById('Terminal' + item.RID);
  if (!iframeElement) return;

  const htmlIframe = iframeElement as HTMLIFrameElement;

  try {
    // 尝试安全地移除事件监听器
    if (htmlIframe.contentWindow) {
      try {
        htmlIframe.contentWindow.removeEventListener('load', () =>
          focusFunc(item),
        );
      } catch (e) {
        console.warn('移除load事件监听器失败:', e);
      }
    }

    // 尝试安全地移除iframe文档的事件监听器
    try {
      const iframeDoc =
        htmlIframe.contentDocument || htmlIframe.contentWindow?.document;
      if (iframeDoc) {
        iframeDoc.removeEventListener('click', function () {
          topDialog(item);
          focusFunc(item);
        });
      }
    } catch (e) {
      console.warn('移除iframe文档事件监听器失败:', e);
    }
  } catch (e) {
    console.warn('访问iframe内容失败:', e);
  }

  // 安全地销毁iframe
  destroyIframe('Terminal' + item.RID);
  delete radioMap.value[item.RID];
}

/**
 * 销毁iframe，释放iframe所占用的内存。
 * @param iframeID
 */
function destroyIframe(iframeID: string) {
  const iframeElement = document.getElementById(iframeID);
  if (!iframeElement) return;

  const htmlIframe = iframeElement as HTMLIFrameElement;

  try {
    // 把iframe指向空白页面，这样可以释放大部分内存
    htmlIframe.src = 'about:blank';

    // 尝试清空iframe内容
    try {
      if (htmlIframe.contentWindow) {
        htmlIframe.contentWindow.document.write('');
        htmlIframe.contentWindow.document.clear();
      }
    } catch (e) {
      console.warn('清空iframe内容失败:', e);
    }

    // 把iframe从页面移除
    if (htmlIframe.parentNode) {
      htmlIframe.parentNode.removeChild(htmlIframe);
    }
  } catch (e) {
    console.warn('销毁iframe失败:', e);
    // 如果发生错误，至少确保iframe被移除
    if (htmlIframe.parentNode) {
      htmlIframe.parentNode.removeChild(htmlIframe);
    }
  }
}

/**
 * 设置iframe聚焦
 * @param item
 */
function focusFunc(item: DialogItem) {
  const iframeElement = document.getElementById('Terminal' + item.RID);
  if (!iframeElement) return;

  const htmlIframe = iframeElement as HTMLIFrameElement;

  // 即使终端窗口是只读的，也不会影响命令输入框
  if (htmlIframe.contentWindow) {
    // 在此处执行方法加载完毕后的代码
    setTimeout(() => {
      if (!radioMap.value[item.RID].read) {
        htmlIframe.focus();
        // 当iframe获得焦点时，移除命令输入框的焦点
        const commandInput = document.getElementById(
          'CommandInput' + item.RID,
        ) as HTMLInputElement;
        if (commandInput) {
          commandInput.blur();
        }
      }
    });
  }
}

/**
 * 点击移动弹窗（修改弹窗层级）
 * @param item
 */
const topDialog = item => {
  currentRID.value = item?.RID;
  emit('topDialog', item);
};

/**
 * 关闭弹窗
 * @param item
 */
const beforeClose = item => {
  closeFunc(item);
  emit('closeDialog', item);
};

// 监听键盘事件，实现命令历史
const handleKeyDown = (e: KeyboardEvent) => {
  const activeRID = currentRID.value;
  if (!activeRID) return;

  // 初始化该终端的历史记录
  initTerminalHistory(activeRID);

  // 只有在命令输入框聚焦且有历史命令时才处理
  if (
    document.activeElement?.id !== 'CommandInput' + activeRID ||
    !commandHistories.value[activeRID].length
  ) {
    return;
  }

  if (e.key === 'ArrowUp') {
    e.preventDefault();
    navigateHistory(activeRID, -1); // 向上浏览历史
  } else if (e.key === 'ArrowDown') {
    e.preventDefault();
    navigateHistory(activeRID, 1); // 向下浏览历史
  }
};

// 浏览命令历史
const navigateHistory = (rid: string, direction: number) => {
  const historyLength = commandHistories.value[rid].length;
  if (!historyLength) return;

  // 计算新的索引位置
  let newIndex = historyIndices.value[rid] + direction;

  // 限制索引范围
  if (newIndex < 0) {
    newIndex = 0;
  } else if (newIndex >= historyLength) {
    newIndex = -1; // -1 表示恢复空白命令行
  }

  historyIndices.value[rid] = newIndex;

  // 如果索引有效，设置命令，否则清空
  if (newIndex >= 0 && newIndex < historyLength) {
    commandInputs.value[rid] =
      commandHistories.value[rid][historyLength - 1 - newIndex];
  } else {
    commandInputs.value[rid] = '';
  }
};

// 设置文本选择功能
const setupTextSelection = () => {
  const overlay = document.querySelector('.text-selection-overlay');
  const selectionArea = overlay?.querySelector('.selection-area');
  let isSelecting = false;
  let startX = 0;
  let startY = 0;
  let selectedText = '';

  // 开始选择文本
  const startSelection = (e: MouseEvent) => {
    isSelecting = true;
    startX = e.clientX;
    startY = e.clientY;

    if (selectionArea && selectionArea instanceof HTMLElement) {
      selectionArea.style.display = 'block';
      selectionArea.style.left = `${startX}px`;
      selectionArea.style.top = `${startY}px`;
      selectionArea.style.width = '0px';
      selectionArea.style.height = '0px';
    }
  };

  // 更新选择区域
  const updateSelection = (e: MouseEvent) => {
    if (!isSelecting) return;

    if (selectionArea && selectionArea instanceof HTMLElement) {
      const width = e.clientX - startX;
      const height = e.clientY - startY;

      selectionArea.style.width = `${Math.abs(width)}px`;
      selectionArea.style.height = `${Math.abs(height)}px`;
      selectionArea.style.left = `${width > 0 ? startX : e.clientX}px`;
      selectionArea.style.top = `${height > 0 ? startY : e.clientY}px`;
    }
  };

  // 结束选择并获取文本
  const endSelection = (e: MouseEvent) => {
    if (!isSelecting) return;
    isSelecting = false;

    // 获取终点
    const endX = e.clientX;
    const endY = e.clientY;

    // 从终端获取选中的文本
    try {
      const activeItem = currentCommandItem.value;
      if (activeItem) {
        const iframe = document.getElementById(
          'Terminal' + activeItem.RID,
        ) as HTMLIFrameElement;
        if (iframe && iframe.contentWindow) {
          // 获取iframe中的选中文本
          const iframeDocument =
            iframe.contentDocument || iframe.contentWindow.document;
          const selection = iframeDocument.getSelection();

          if (selection && selection.toString().trim()) {
            selectedText = selection.toString();
            // 将选中文本复制到剪贴板（使用安全的复制方法）
            copyToClipboard(selectedText).then(success => {
              if (success) {
                // 显示复制成功的提示
                ElMessage({
                  message: '文本已复制到剪贴板',
                  type: 'success',
                  duration: 1500,
                  offset: 60,
                  customClass: 'copy-success-message',
                });

                // 显示复制内容预览
                showCopyPreview(selectedText, e.clientX, e.clientY);
              } else {
                ElMessage.warning('复制失败，浏览器阻止了复制操作');
              }
            });
          }
        }
      }
    } catch (error) {
      console.error('获取选中文本失败:', error);
    }

    // 隐藏选择区域
    if (selectionArea && selectionArea instanceof HTMLElement) {
      selectionArea.style.display = 'none';
    }
  };

  // 处理复制快捷键
  const handleCopyShortcut = (e: KeyboardEvent) => {
    if ((e.ctrlKey || e.metaKey) && e.key === 'c') {
      // 检查当前是否有选中的iframe和选中文本
      const activeItem = currentCommandItem.value;
      if (activeItem) {
        const iframe = document.getElementById(
          'Terminal' + activeItem.RID,
        ) as HTMLIFrameElement;
        if (iframe && iframe.contentWindow) {
          const iframeDocument =
            iframe.contentDocument || iframe.contentWindow.document;
          const selection = iframeDocument.getSelection();

          if (selection && selection.toString().trim()) {
            e.preventDefault();
            const text = selection.toString();

            // 使用安全的复制方法
            copyToClipboard(text).then(success => {
              if (success) {
                ElMessage({
                  message: '文本已复制到剪贴板',
                  type: 'success',
                  duration: 1500,
                  offset: 60,
                  customClass: 'copy-success-message',
                });

                // 预览复制的内容
                const rect = selection.getRangeAt(0).getBoundingClientRect();
                showCopyPreview(text, rect.right, rect.top);
              } else {
                ElMessage.warning('复制失败，浏览器阻止了复制操作');
              }
            });
          }
        }
      }
    }
  };

  // 添加事件监听
  if (overlay) {
    overlay.addEventListener('mousedown', startSelection);
    overlay.addEventListener('mousemove', updateSelection);
    overlay.addEventListener('mouseup', endSelection);
  }
  document.addEventListener('keydown', handleCopyShortcut);

  // 在组件卸载时移除事件监听器
  onBeforeUnmount(() => {
    if (overlay) {
      overlay.removeEventListener('mousedown', startSelection);
      overlay.removeEventListener('mousemove', updateSelection);
      overlay.removeEventListener('mouseup', endSelection);
    }
    document.removeEventListener('keydown', handleCopyShortcut);
  });
};

/**
 * 显示复制的文本预览
 * @param text 复制的文本
 * @param x 显示位置的x坐标
 * @param y 显示位置的y坐标
 */
const showCopyPreview = (text: string, x: number, y: number) => {
  // 创建或获取预览元素
  let preview = document.querySelector('.copy-preview') as HTMLElement;
  if (!preview) {
    preview = document.createElement('div');
    preview.className = 'copy-preview';
    document.body.appendChild(preview);
  }

  // 显示预览内容
  let previewContent = text;
  // 截取预览内容，太长的文本显示部分内容加省略号
  if (previewContent.length > 60) {
    previewContent = previewContent.substring(0, 57) + '...';
  }

  // 设置内容和样式
  preview.textContent = previewContent;
  preview.style.left = `${x - preview.offsetWidth / 2}px`;
  preview.style.top = `${y - 50}px`;
  preview.classList.add('show');

  // 一段时间后隐藏预览
  setTimeout(() => {
    preview.classList.remove('show');
  }, 1500);
};

/**
 * 复制当前选中的文本
 */
const copySelectedText = () => {
  const activeItem = currentCommandItem.value;
  if (!activeItem) {
    ElMessage.warning('请先选择一个终端');
    return;
  }

  const iframe = document.getElementById(
    'Terminal' + activeItem.RID,
  ) as HTMLIFrameElement;

  if (iframe && iframe.contentWindow) {
    const iframeDocument =
      iframe.contentDocument || iframe.contentWindow.document;
    const selection = iframeDocument.getSelection();

    if (selection && selection.toString().trim()) {
      const text = selection.toString();

      // 使用安全的复制方法
      copyToClipboard(text).then(success => {
        if (success) {
          ElMessage({
            message: '文本已复制到剪贴板',
            type: 'success',
            duration: 1500,
            offset: 60,
            customClass: 'copy-success-message',
          });

          // 获取按钮位置并显示复制内容预览
          const copyButton = document.querySelector('.copy-button');
          if (copyButton && copyButton instanceof HTMLElement) {
            const rect = copyButton.getBoundingClientRect();
            showCopyPreview(text, rect.left + rect.width / 2, rect.top);
          }
        } else {
          ElMessage.warning('复制失败，浏览器阻止了复制操作');
        }
      });
    } else {
      ElMessage.warning('没有选中文本');
    }
  } else {
    ElMessage.error('无法访问终端');
  }
};

/**
 * 安全的复制文本到剪贴板方法，提供多种实现方式
 * @param text 要复制的文本
 * @returns Promise<boolean> 是否成功复制
 */
const copyToClipboard = async (text: string): Promise<boolean> => {
  // 方法1: 尝试使用现代Clipboard API
  if (
    navigator.clipboard &&
    typeof navigator.clipboard.writeText === 'function'
  ) {
    try {
      await navigator.clipboard.writeText(text);
      return true;
    } catch (err) {
      console.warn('Clipboard API失败，尝试备用方法:', err);
      // 失败时继续尝试备用方法
    }
  }

  // 方法2: 使用document.execCommand (兼容性更好但已弃用)
  try {
    // 创建临时DOM元素
    const textArea = document.createElement('textarea');
    textArea.value = text;

    // 确保元素不可见
    textArea.style.position = 'fixed';
    textArea.style.top = '0';
    textArea.style.left = '0';
    textArea.style.width = '2em';
    textArea.style.height = '2em';
    textArea.style.padding = '0';
    textArea.style.border = 'none';
    textArea.style.outline = 'none';
    textArea.style.boxShadow = 'none';
    textArea.style.background = 'transparent';
    textArea.style.opacity = '0';

    document.body.appendChild(textArea);
    textArea.focus();
    textArea.select();

    // 执行复制命令
    const success = document.execCommand('copy');
    document.body.removeChild(textArea);
    return success;
  } catch (err) {
    console.error('execCommand复制方法失败:', err);
    return false;
  }
};

// 添加启用/禁用文本选择功能
const toggleTextSelection = (enable: boolean) => {
  const overlay = document.querySelector('.text-selection-overlay');
  if (overlay && overlay instanceof HTMLElement) {
    if (enable) {
      overlay.classList.add('active');
    } else {
      overlay.classList.remove('active');
    }
  }
};

/**
 * 切换虚拟键盘显示状态
 */
const toggleVirtualKeyboard = () => {
  showVirtualKeyboard.value = !showVirtualKeyboard.value;
};

/**
 * 切换Shift键状态
 */
const toggleShift = () => {
  isShiftActive.value = !isShiftActive.value;
};

/**
 * 发送普通按键
 * @param item 虚拟机项
 * @param key 按键
 */
const sendKey = (item: DialogItem, key: string) => {
  // 如果shift键激活且发送的是字母，转换为大写
  if (isShiftActive.value) {
    if (key.match(/[a-z]/)) {
      key = key.toUpperCase();
    } else {
      // 处理shift+数字或特殊符号
      const shiftMapping: Record<string, string> = {
        '`': '~',
        '1': '!',
        '2': '@',
        '3': '#',
        '4': '$',
        '5': '%',
        '6': '^',
        '7': '&',
        '8': '*',
        '9': '(',
        '0': ')',
        '-': '_',
        '=': '+',
        '[': '{',
        ']': '}',
        '\\': '|',
        ';': ':',
        "'": '"',
        ',': '<',
        '.': '>',
        '/': '?',
      };

      if (shiftMapping[key]) {
        key = shiftMapping[key];
      }
    }

    // 发送后自动取消shift状态，模拟实际键盘使用
    isShiftActive.value = false;
  }

  sendTextToVirtualMachine(item, key);
};

/**
 * 发送特殊按键
 * @param item 虚拟机项
 * @param key 特殊按键
 */
const sendSpecialKey = (item: DialogItem, key: string) => {
  // 直接访问iframe文档
  const iframe = document.getElementById('Terminal' + item.RID);
  if (!iframe) return;

  const htmlIframe = iframe as HTMLIFrameElement;
  const iframeDocument =
    htmlIframe.contentDocument || htmlIframe.contentWindow?.document;
  if (!iframeDocument) return;

  let keyCode = 0;

  // 映射特殊按键的keyCode
  switch (key) {
    case 'Enter':
      keyCode = 13;
      break;
    case 'Tab':
      keyCode = 9;
      break;
    case 'Backspace':
      keyCode = 8;
      break;
    case 'Esc':
      keyCode = 27;
      break;
    case 'ArrowUp':
      keyCode = 38;
      break;
    case 'ArrowDown':
      keyCode = 40;
      break;
    case 'ArrowLeft':
      keyCode = 37;
      break;
    case 'ArrowRight':
      keyCode = 39;
      break;
    case 'CapsLock':
      toggleShift(); // 简化处理，直接切换Shift状态
      return;
    default:
      // 处理F1-F12按键
      if (key.startsWith('F') && key.length <= 3) {
        const fNum = parseInt(key.substring(1));
        if (fNum >= 1 && fNum <= 12) {
          keyCode = 111 + fNum;
        }
      }
      break;
  }

  if (keyCode > 0) {
    // 创建并发送键盘事件
    const keyDown = new KeyboardEvent('keydown', {
      key: key,
      code: key,
      keyCode: keyCode,
      which: keyCode,
      bubbles: true,
    });

    // 确保焦点在iframe上
    focusFunc(item);

    // 模拟按键事件
    setTimeout(() => {
      if (iframeDocument.activeElement) {
        iframeDocument.activeElement.dispatchEvent(keyDown);
      } else {
        iframeDocument.dispatchEvent(keyDown);
      }

      // 对于某些需要模拟输入事件的特殊键，添加额外处理
      if (key === 'Enter') {
        sendTextToVirtualMachine(item, '\n');
      } else if (key === 'Tab') {
        sendTextToVirtualMachine(item, '\t');
      }
    }, 50);
  }
};

/**
 * 切换只读模式
 */
const toggleReadOnly = () => {
  if (currentRID.value) {
    const currentItem = props.dialogList.find(
      item => item.RID === currentRID.value,
    );

    if (currentItem) {
      // 更新当前终端的只读状态
      radioMap.value[currentRID.value].read =
        !radioMap.value[currentRID.value].read;

      // 调用changeVirtual方法应用更改
      changeVirtual(currentItem);

      // 如果是切换到只读模式，移除焦点
      if (radioMap.value[currentRID.value].read) {
        const iframe = document.getElementById(
          'Terminal' + currentRID.value,
        ) as HTMLIFrameElement;
        if (iframe) {
          iframe.blur();
        }
      }

      // 显示状态变更提示
      ElMessage({
        message: radioMap.value[currentRID.value].read
          ? '已切换为只读模式'
          : '已切换为可编辑模式',
        type: 'success',
        duration: 1500,
      });
    }
  }
};

/**
 * 打开系统软键盘 (发送Ctrl+Shift+Alt组合键)
 */
const openSystemKeyboard = (item: DialogItem) => {
  const iframe = document.getElementById('Terminal' + item.RID);
  if (!iframe) return;

  const htmlIframe = iframe as HTMLIFrameElement;
  const iframeDocument =
    htmlIframe.contentDocument || htmlIframe.contentWindow?.document;
  if (!iframeDocument) return;

  // 确保iframe获得焦点
  focusFunc(item);

  // 模拟Ctrl+Shift+Alt组合键
  setTimeout(() => {
    if (iframeDocument.activeElement) {
      // 按下Ctrl键
      const ctrlDown = new KeyboardEvent('keydown', {
        key: 'Control',
        code: 'ControlLeft',
        keyCode: 17,
        which: 17,
        ctrlKey: true,
        bubbles: true,
      });
      iframeDocument.activeElement.dispatchEvent(ctrlDown);

      // 按下Shift键
      const shiftDown = new KeyboardEvent('keydown', {
        key: 'Shift',
        code: 'ShiftLeft',
        keyCode: 16,
        which: 16,
        shiftKey: true,
        ctrlKey: true,
        bubbles: true,
      });
      iframeDocument.activeElement.dispatchEvent(shiftDown);

      // 按下Alt键
      const altDown = new KeyboardEvent('keydown', {
        key: 'Alt',
        code: 'AltLeft',
        keyCode: 18,
        which: 18,
        altKey: true,
        ctrlKey: true,
        shiftKey: true,
        bubbles: true,
      });
      iframeDocument.activeElement.dispatchEvent(altDown);

      // 释放Alt键
      const altUp = new KeyboardEvent('keyup', {
        key: 'Alt',
        code: 'AltLeft',
        keyCode: 18,
        which: 18,
        altKey: false,
        ctrlKey: true,
        shiftKey: true,
        bubbles: true,
      });
      iframeDocument.activeElement.dispatchEvent(altUp);

      // 释放Shift键
      const shiftUp = new KeyboardEvent('keyup', {
        key: 'Shift',
        code: 'ShiftLeft',
        keyCode: 16,
        which: 16,
        shiftKey: false,
        ctrlKey: true,
        bubbles: true,
      });
      iframeDocument.activeElement.dispatchEvent(shiftUp);

      // 释放Ctrl键
      const ctrlUp = new KeyboardEvent('keyup', {
        key: 'Control',
        code: 'ControlLeft',
        keyCode: 17,
        which: 17,
        ctrlKey: false,
        bubbles: true,
      });
      iframeDocument.activeElement.dispatchEvent(ctrlUp);
    }
  }, 100);
};

// 子组件暴露方法
defineExpose({
  openFunc,
  focusFunc,
});

// 添加输入框事件监听
const handleInput = (event: InputEvent) => {
  const input = event.target as HTMLInputElement;
  const value = input.value;

  // 直接移除中文字符，不显示提示
  input.value = value.replace(/[\u4e00-\u9fa5]/g, '');
};

/**
 * 处理命令输入框点击事件
 */
const handleCommandInputClick = (item: DialogItem) => {
  // 设置当前激活的终端
  currentRID.value = item.RID;

  // 获取iframe元素
  const iframe = document.getElementById(
    'Terminal' + item.RID,
  ) as HTMLIFrameElement;
  if (iframe) {
    // 移除iframe的焦点
    iframe.blur();

    // 确保iframe不会捕获焦点
    iframe.style.pointerEvents = 'none';

    // 短暂延迟后恢复iframe的指针事件
    setTimeout(() => {
      iframe.style.pointerEvents = 'auto';
    }, 100);
  }

  // 聚焦到命令输入框
  nextTick(() => {
    const inputElement = document.getElementById('CommandInput' + item.RID);
    if (inputElement) {
      inputElement.focus();
    }
  });
};
</script>

<style lang="scss" scoped>
/* 终端窗口样式 - 使用局部作用域 */
.terminal-window {
  width: 100%;
  height: 100%;
  background-color: #0c0c0c;
  border-radius: 8px;
  overflow: hidden;
  box-shadow: 0 8px 30px rgba(0, 0, 0, 0.4);
  transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
  border: 1px solid #222;
  display: flex;
  flex-direction: column;
  position: relative;

  &.active-terminal {
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(50, 205, 50, 0.2);
    border-color: #2d2d2d;
  }
}

/* 调整dragSize组件的最大化图标样式 */
:deep(.drag-size-maximize) {
  position: absolute;
  top: 10px;
  right: 10px;
  width: 24px;
  height: 24px;
  background-color: rgba(50, 205, 50, 0.2);
  border: 1px solid rgba(50, 205, 50, 0.4);
  border-radius: 4px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: all 0.3s ease;
  z-index: 1000;

  &:hover {
    background-color: rgba(50, 205, 50, 0.3);
    transform: scale(1.1);
  }

  svg {
    width: 16px;
    height: 16px;
    color: #32cd32;
  }
}

.terminal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 40px;
  padding: 0 10px;
  background: linear-gradient(180deg, #1a1a1a 0%, #2a2a2a 100%);
  position: relative;
  overflow: hidden;

  &::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 1px;
    background: linear-gradient(
      90deg,
      rgba(76, 175, 80, 0.1),
      rgba(76, 175, 80, 0.6),
      rgba(76, 175, 80, 0.1)
    );
  }
}

.terminal-controls {
  display: flex;
  gap: 8px;
}

.control-button {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  transition: all 0.2s ease;
  cursor: pointer;
  position: relative;

  &::before {
    content: '';
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%) scale(0);
    width: 6px;
    height: 6px;
    background-color: rgba(0, 0, 0, 0.5);
    border-radius: 50%;
    transition: transform 0.2s ease;
  }

  &:hover::before {
    transform: translate(-50%, -50%) scale(1);
  }

  &.close {
    background-color: #ff5f56;
    &:active {
      background-color: #e04343;
    }
  }

  &.minimize {
    background-color: #ffbd2e;
    &:active {
      background-color: #e0a92a;
    }
  }

  &.expand {
    background-color: #27c93f;
    &:active {
      background-color: #1daa31;
    }
  }
}

.terminal-title {
  display: flex;
  align-items: center;
  gap: 10px;
  color: #f0f0f0;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.5px;
}

.terminal-actions {
  display: flex;
  align-items: center;
  gap: 15px;

  .action-button {
    width: 28px;
    height: 28px;
    border-radius: 4px;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #f0f0f0;
    cursor: pointer;
    background-color: rgba(255, 255, 255, 0.1);
    transition: all 0.2s ease;
    font-size: 18px;

    &:hover {
      background-color: rgba(255, 255, 255, 0.2);
      transform: translateY(-1px);
    }

    &:active {
      transform: translateY(0);
    }

    &.keyboard-button {
      background-color: rgba(39, 201, 63, 0.15);
      color: #32cd32;

      &:hover {
        background-color: rgba(39, 201, 63, 0.25);
      }
    }
  }

  .readonly-indicator {
    display: flex;
    align-items: center;
    gap: 5px;
    background-color: rgba(39, 201, 63, 0.1);
    padding: 2px 8px;
    border-radius: 10px;
    border: 1px solid rgba(39, 201, 63, 0.2);
    position: absolute;
    top: 5px;
    right: 5px;
    transition: all 0.3s ease;

    &.active {
      background-color: rgba(255, 189, 46, 0.1);
      border: 1px solid rgba(255, 189, 46, 0.2);

      .status-dot {
        background-color: #ffbd2e;
        box-shadow: 0 0 0 rgba(255, 189, 46, 0.4);
        animation: pulse-yellow 2s infinite;
      }

      .status-text {
        color: #ffbd2e;
      }
    }

    .status-dot {
      width: 6px;
      height: 6px;
      border-radius: 50%;
      background-color: #27c93f;
      box-shadow: 0 0 0 rgba(39, 201, 63, 0.4);
      animation: pulse-green 2s infinite;
    }

    .status-text {
      font-size: 11px;
      color: #27c93f;
    }
  }

  .mode-toggle {
    .el-switch {
      --el-switch-on-color: #27c93f;
    }
  }
}

/* 虚拟键盘样式 */
.virtual-keyboard {
  width: 100%;
  background-color: rgba(20, 20, 20, 0.95);
  border-top: 1px solid #333;
  padding: 10px;
  position: absolute;
  bottom: 64px;
  left: 0;
  right: 0;
  z-index: 100;
  box-shadow: 0 -4px 20px rgba(0, 0, 0, 0.4);
  animation: slide-up 0.3s ease;

  .keyboard-controls {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding-bottom: 10px;
    margin-bottom: 10px;
    border-bottom: 1px solid #333;

    span {
      color: #ccc;
      font-weight: 500;
    }

    .keyboard-close {
      width: 24px;
      height: 24px;
      display: flex;
      align-items: center;
      justify-content: center;
      color: #ccc;
      background-color: rgba(255, 255, 255, 0.1);
      border-radius: 4px;
      cursor: pointer;
      font-size: 16px;
      font-weight: bold;

      &:hover {
        background-color: rgba(255, 255, 255, 0.2);
        color: white;
      }
    }
  }

  .keyboard-row {
    display: flex;
    justify-content: center;
    gap: 5px;
    margin-bottom: 5px;
    flex-wrap: wrap;

    &:last-child {
      margin-bottom: 0;
    }

    .keyboard-key {
      display: flex;
      align-items: center;
      justify-content: center;
      width: 40px;
      height: 36px;
      background-color: #2a2a2a;
      color: #f0f0f0;
      border-radius: 4px;
      cursor: pointer;
      font-size: 12px;
      box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
      user-select: none;
      border: 1px solid #444;

      &:hover {
        background-color: #3a3a3a;
      }

      &:active {
        transform: translateY(1px);
        box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
      }

      &.wide-key {
        width: 80px;
      }

      &.wider-key {
        width: 60px;
      }

      &.widest-key {
        width: 100px;
      }

      &.function-key {
        background-color: #31363f;
        color: #2cc652;
      }

      &.arrow-key {
        background-color: #31363f;
        font-size: 16px;
      }
    }

    &.arrow-container {
      display: flex;
      gap: 5px;
    }
  }
}

@keyframes slide-up {
  from {
    transform: translateY(100%);
    opacity: 0;
  }
  to {
    transform: translateY(0);
    opacity: 1;
  }
}

@keyframes pulse-green {
  0% {
    box-shadow: 0 0 0 0 rgba(39, 201, 63, 0.4);
  }
  70% {
    box-shadow: 0 0 0 6px rgba(39, 201, 63, 0);
  }
  100% {
    box-shadow: 0 0 0 0 rgba(39, 201, 63, 0);
  }
}

@keyframes pulse-yellow {
  0% {
    box-shadow: 0 0 0 0 rgba(255, 189, 46, 0.4);
  }
  70% {
    box-shadow: 0 0 0 6px rgba(255, 189, 46, 0);
  }
  100% {
    box-shadow: 0 0 0 0 rgba(255, 189, 46, 0);
  }
}

.terminal-container {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
  background-color: #121212;
  position: relative;
}

.virtualIframe {
  padding: unset;
  border-radius: unset;
  width: 100%;
  flex: 1; /* 使iframe占据所有可用空间 */
  min-height: 0; /* 允许iframe缩小 */
  overflow: hidden;
  position: relative;
  transition: height 0.3s ease;

  &.full-height {
    height: 100%; /* 在只读模式下占据全部高度 */
  }

  .iframeMain {
    width: 100%;
    height: 100%;
    transition: opacity 0.3s ease;
    position: relative;

    &.readonly {
      iframe {
        pointer-events: none;
        -moz-user-select: none; /*火狐*/
        -webkit-user-select: none; /*webkit浏览器*/
        -ms-user-select: none; /*IE10*/
        user-select: none;
      }
    }

    iframe {
      background-color: #000;
      transition: opacity 0.5s ease;
      opacity: 0.98;

      &:hover {
        opacity: 1;
      }
    }

    // 文本选择覆盖层
    .text-selection-overlay {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      background: transparent;
      display: none;
      z-index: 10;
      cursor: text;

      &.active {
        display: block;
      }

      .selection-area {
        position: absolute;
        background-color: rgba(76, 175, 80, 0.3);
        border: 1px solid rgba(76, 175, 80, 0.5);
        display: none;
        pointer-events: none;
        border-radius: 2px;
        box-shadow: 0 0 10px rgba(76, 175, 80, 0.2);
      }
    }
  }

  .mask {
    width: calc(100% - 2px);
    height: 100%;
    position: absolute;
    top: 0;
    left: 0;
    transition: background-color 0.2s ease, height 0.2s ease;

    &:not(.active) {
      background-color: rgba(0, 0, 0, 0.05);
      backdrop-filter: blur(0.5px);
    }

    &.active {
      height: 0;
    }
  }

  .iframe-loading {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: rgba(0, 0, 0, 0.8);
    display: flex;
    justify-content: center;
    align-items: center;
    z-index: 100;

    .loading-spinner {
      width: 40px;
      height: 40px;
      border: 3px solid rgba(50, 205, 50, 0.1);
      border-radius: 50%;
      border-top-color: #32cd32;
      animation: spin 1s ease-in-out infinite;
    }
  }
}

.command-console {
  width: 100%;
  height: 60px;
  background: linear-gradient(to bottom, #252525, #1a1a1a);
  border-top: 1px solid #333;
  display: flex;
  align-items: center;
  padding: 0 16px;
  box-sizing: border-box;
  cursor: text;
  transition: background 0.3s ease;
  margin-top: auto;
  position: relative;
  z-index: 1000; // 确保命令控制台在最上层

  &:hover {
    background: linear-gradient(to bottom, #272727, #1c1c1c);
  }

  .console-prefix {
    color: #32cd32;
    font-family: 'Consolas', monospace;
    font-weight: bold;
    font-size: 18px;
    margin-right: 12px;
    animation: blink 1.5s step-end infinite;
  }

  .console-input {
    flex: 1;
    background-color: rgba(0, 0, 0, 0.25);
    border: 1px solid #444;
    outline: none;
    color: #f0f0f0;
    font-family: 'Consolas', monospace;
    font-size: 16px;
    line-height: 24px;
    height: 40px;
    padding: 0 12px;
    border-radius: 4px;
    box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.3);
    transition: all 0.2s ease;
    caret-color: #32cd32;
    margin-right: 10px;
    position: relative;
    z-index: 1001;

    &:focus {
      background-color: rgba(0, 0, 0, 0.3);
      border-color: #666;
      box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.4),
        0 0 0 2px rgba(50, 205, 50, 0.2);
    }

    &::placeholder {
      color: #888;
    }
  }

  .console-send-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border-radius: 4px;
    background-color: rgba(50, 205, 50, 0.1);
    color: #32cd32;
    cursor: pointer;
    transition: all 0.2s ease;

    &:hover {
      background-color: rgba(50, 205, 50, 0.2);
      transform: translateY(-2px);
      box-shadow: 0 2px 8px rgba(50, 205, 50, 0.15);
    }

    &:active {
      background-color: rgba(50, 205, 50, 0.3);
      transform: scale(0.95) translateY(0);
      box-shadow: 0 1px 3px rgba(50, 205, 50, 0.2);
    }

    svg {
      transition: transform 0.2s ease;
    }

    &:hover svg {
      transform: translateX(2px);
    }
  }
}

/* 动画定义 */
@keyframes pulse {
  0% {
    opacity: 0.6;
  }
  50% {
    opacity: 1;
  }
  100% {
    opacity: 0.6;
  }
}

@keyframes blink {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.5;
  }
}

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

/* Dialog content styles - 保持原有样式的类名，确保不影响外部 */
.dialog_content {
  width: 100%;
  height: 100%;
}

// 新增复制预览效果
.copy-preview {
  position: fixed;
  background-color: rgba(76, 175, 80, 0.9);
  color: white;
  padding: 5px 12px;
  border-radius: 4px;
  font-size: 12px;
  z-index: 9999;
  opacity: 0;
  transform: translateY(10px);
  transition: opacity 0.2s ease, transform 0.2s ease;
  pointer-events: none;
  white-space: nowrap;
  max-width: 400px;
  overflow: hidden;
  text-overflow: ellipsis;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);

  &.show {
    opacity: 1;
    transform: translateY(0);
  }
}

// 复制成功消息样式
:global(.copy-success-message) {
  background-color: rgba(76, 175, 80, 0.9) !important;
  border: none !important;
  color: white !important;
}

/* 悬浮控制按钮 */
.floating-controls {
  position: absolute;
  top: 10px;
  right: 10px;
  display: flex;
  gap: 8px;
  z-index: 100;
  opacity: 0.8;
  transition: all 0.3s ease;
  background-color: rgba(0, 0, 0, 0.7);
  padding: 6px;
  border-radius: 8px;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.3);

  &:hover {
    opacity: 1;
    transform: translateY(-1px);
  }

  .control-indicator {
    width: 38px;
    height: 38px;
    border-radius: 8px;
    background-color: rgba(255, 255, 255, 0.15);
    border: 1px solid rgba(255, 255, 255, 0.2);
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: all 0.3s ease;
    font-size: 16px;

    &:hover {
      background-color: rgba(255, 255, 255, 0.25);
      border-color: rgba(255, 255, 255, 0.3);
      transform: translateY(-1px);
    }

    &.active {
      background-color: rgba(255, 189, 46, 0.2);
      border-color: rgba(255, 189, 46, 0.5);
      color: #ffbd2e;

      &:hover {
        background-color: rgba(255, 189, 46, 0.3);
      }
    }

    &:not(.active) {
      background-color: rgba(50, 205, 50, 0.2);
      border-color: rgba(50, 205, 50, 0.4);
      color: #32cd32;

      &:hover {
        background-color: rgba(50, 205, 50, 0.3);
      }
    }

    &:hover {
      transform: translateY(-1px);
      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
      background-color: rgba(0, 0, 0, 0.7);
      color: #fff;
    }

    &:active {
      transform: translateY(0);
    }

    &.keyboard-indicator {
      background-color: rgba(50, 205, 50, 0.2);
      border-color: rgba(50, 205, 50, 0.4);
      color: #32cd32;

      &:hover {
        background-color: rgba(50, 205, 50, 0.3);
      }

      i {
        animation: pulse-green 4s infinite;
      }

      svg {
        animation: pulse-green 4s infinite;
      }
    }

    &.status-readonly-indicator {
      background-color: rgba(50, 205, 50, 0.2);
      border-color: rgba(50, 205, 50, 0.4);
      color: #32cd32;

      svg {
        animation: pulse-green 4s infinite;
      }
    }

    &.status-readonly-indicator.active {
      background-color: rgba(255, 189, 46, 0.2);
      border-color: rgba(255, 189, 46, 0.5);
      color: #ffbd2e;

      &:hover {
        background-color: rgba(255, 189, 46, 0.3);
      }

      i {
        animation: pulse-yellow 2s infinite;
      }

      svg {
        animation: pulse-yellow 2s infinite;
      }
    }

    svg {
      width: 18px; /* 增大SVG图标 */
      height: 18px;
    }
  }
}

/* 状态提示样式 */
.status-indicator-common {
  position: absolute;
  top: 20px;
  left: 20px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  background: rgba(39, 201, 63, 0.1);
  border-radius: 50%;
  z-index: 1000;
  backdrop-filter: blur(10px);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  border: 1px solid rgba(39, 201, 63, 0.3);
  cursor: pointer;
  transition: all 0.3s ease;

  &:hover {
    transform: scale(1.1);
    background: rgba(39, 201, 63, 0.2);
  }

  &.readonly-mode {
    background: rgba(255, 189, 46, 0.1);
    border-color: rgba(255, 189, 46, 0.3);

    .status-icon {
      color: #ffbd2e;
    }

    &:hover {
      background: rgba(255, 189, 46, 0.2);
    }
  }

  .status-icon {
    color: #27c93f;
    display: flex;
    align-items: center;
    justify-content: center;
    position: relative;

    &::after {
      content: '';
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      width: 100%;
      height: 100%;
      border-radius: 50%;
      background: currentColor;
      opacity: 0.1;
      animation: icon-pulse 2s ease-out infinite;
    }
  }
}

@keyframes icon-pulse {
  0% {
    transform: translate(-50%, -50%) scale(1);
    opacity: 0.1;
  }
  50% {
    transform: translate(-50%, -50%) scale(1.5);
    opacity: 0.05;
  }
  100% {
    transform: translate(-50%, -50%) scale(1);
    opacity: 0.1;
  }
}

/* 只读模式样式 */
.iframeMain.readonly {
  iframe {
    pointer-events: none;
    -moz-user-select: none;
    -webkit-user-select: none;
    -ms-user-select: none;
    user-select: none;
  }
}

/* 命令控制台在只读模式下的样式 */
.command-console {
  &.readonly {
    opacity: 0.5;
    pointer-events: none;
  }
}
</style>
